#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <functional>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders; // 允许在程序中使用占位符 _1, _2, _3

// 1. 组合TCPserver对象
// 2. 创建EventLoop 事件循环对象的指针
// 3. 明确TcpServer 创造函数要什么参数
// 4. 在当前服务器类的构造函数中，注册处理连接和读写事件的回调函数
// 5. 设置合适的  线程数量
// 6.
class ChatServer
{
public:
    ChatServer(EventLoop *loop,               // 事件循环
               const InetAddress &listenAddr, // IP+ port
               const string &nameArg)         // 服务器名字
        : _server(loop, listenAddr, nameArg), _loop(loop)
    {
        // 当相应事件发生，就会调用对应的回调函数
        // 给服务器注册用户链接的创建和断开回调
        _server.setConnectionCallback(bind(&ChatServer::onConnection, this, _1));
        //_1占位符，指onConnection的第一个参数

        // 给服务器注册用户读写事件回调
        _server.setMessageCallback(bind(&ChatServer::onMessage, this, _1, _2, _3));

        // 设置服务器端的线程数量 , 一个IO线程，　３个工作线程　　－－》与CPU核数类似
        _server.setThreadNum(4);
    }

    // 开启事件循环
    void start()
    {
        _server.start();
    }

private:
    // 专门处理用户的连接的创建和断开 epoll listenfd accpet
    void onConnection(const TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << " start " << endl;
        }
        else
        {
            cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << " unconnect " << endl;
            conn->shutdown(); // close(fd);
        }
    }
    // 专门处理用户的读写事件
    void onMessage(const TcpConnectionPtr & conn, // 链接
                   Buffer *buffer,                 // 缓冲区
                   Timestamp time)           // 接收到数据的事件信息
    {
        string buf = buffer->retrieveAllAsString();
        cout<<"recv data:" << buf <<" time: "<<time.toString() <<endl;
        conn->send(buf);
    }
    TcpServer _server;
    EventLoop *_loop;
};

int main()
{
    EventLoop loop; //epoll
    InetAddress addr("127.0.0.1",6000);
    ChatServer server(&loop,addr,"CharServer");

    server.start();//启动服务， listenfd -->  添加到 epoll上
    loop.loop(); //epoll_wait 以阻塞的方式等待新用户的链接 和已链接用户的读写事件
    return 0;
}